/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package graf;

import bledy.BladGrafu;
import bledy.BladKonca;
import bledy.BladPoczatku;
import formatki.WidokGrafu;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author marek
 */
public class Graf {

    private List<Wierzcholek> wierzcholki = new ArrayList<Wierzcholek>();
    private List<Wierzcholek> poczatkowe = new ArrayList<Wierzcholek>();
    private List<Wierzcholek> koncowe = new ArrayList<Wierzcholek>();
    private Set<String> definicje = new HashSet<String>();

    public Graf() {
    }

    public List<Wierzcholek> getKoncowe() {
        return koncowe;
    }

    public List<Wierzcholek> getPoczatkowe() {
        return poczatkowe;
    }

    public List<Wierzcholek> getWierzcholki() {
        return wierzcholki;
    }

    public boolean isPoczatkowy(Wierzcholek w) {
        return poczatkowe.contains(w);
    }

    public boolean isKoncowy(Wierzcholek w) {
        return koncowe.contains(w);
    }

    public Set<String> getDefinicje() {
        return definicje;
    }

    //sprawadza czy istnieje taki w liscie
    public boolean czyZawieraWierzcholek(int n) {
        for (Wierzcholek w : wierzcholki) {
            if (w.getNumer() == n) {
                return true;
            }
        }
        return false;
    }

    //pobiera wierzcholek
    public Wierzcholek pobierzWierzcholek(int n) {
        for (Wierzcholek w : wierzcholki) {
            if (w.getNumer() == n) {
                return w;
            }
        }
        return null;
    }

    //dodaje wierzcholek kon do wierzcholkow i zwraca go
    //jesli juz istnieje to tylko zwraca
    public Wierzcholek dodajWierzcholek(int kon, WidokGrafu widokGrafu) {
        if (!czyZawieraWierzcholek(kon)) {
            Wierzcholek w = new Wierzcholek();
            w.setNumer(kon);
            w.setX(widokGrafu.getNextX());
            w.setY(widokGrafu.getNextY());
            getWierzcholki().add(w);
            return w;
        }
        return pobierzWierzcholek(kon);
    }

    //dodaje wierzcholek pocz do listy wierzcholkow
    //i dodaje wK do jego sasiadow
    //jesli pocz juz istnieje to tylko dodaje sasiada
    public void dodajWierzcholek(int pocz, Wierzcholek wK, WidokGrafu widokGrafu) {
        if (!czyZawieraWierzcholek(pocz)) {
            Wierzcholek w = new Wierzcholek();
            w.setNumer(pocz);

            w.setX(widokGrafu.getNextX());
            w.setY(widokGrafu.getNextY());
            w.getSasiedzi().add(new WierzcholekPlusPlus(wK));
            getWierzcholki().add(w);
        } else {
            Wierzcholek w = pobierzWierzcholek(pocz);
            if (!w.czyZawieraSasiada(wK)) {
                w.getSasiedzi().add(new WierzcholekPlusPlus(wK));
            }
        }
    }

    //dodaje wierzcholek o numerze do poczatkowych
    //jesli ten wierzcholek nie jest jeszcze w liscie wierzcholkow 
    //to go dodaje
    public void dodajPocz(Integer numer, WidokGrafu widokGrafu) {
        Wierzcholek w = dodajWierzcholek(numer, widokGrafu);
        w.setPoczatkowy(true);
        if (!getPoczatkowe().contains(w)) {
            getPoczatkowe().add(w);
        }
    }

    //dodaje wierzcholek o numerze do koncowych
    //jesli ten wierzcholek nie jest jeszcze w liscie wierzcholkow
    //to go dodaje
    public void dodajKon(Integer numer, WidokGrafu widokGrafu) {
        Wierzcholek w = dodajWierzcholek(numer, widokGrafu);
        w.setKoncowy(true);
        if (!getKoncowe().contains(w)) {
            getKoncowe().add(w);
        }
    }

    //odznacza wszystkie wierzcholki z odwiedzonego na nieodwiedzone
    public void odswiezWierzcholki() {
        for (int i = 0; i < this.wierzcholki.size(); ++i) {
            this.wierzcholki.get(i).setOdwiedzony(false);
        }
    }


    public boolean obliczOdleglosci(Wierzcholek wStart, Wierzcholek wKoniec){
        for(Wierzcholek w : this.getWierzcholki()){
            w.setOdlStart(-1);
            w.setOdlKoniec(-1);
        }
        wStart.setOdlStart(0);
        for(WierzcholekPlusPlus ws : wStart.getSasiedzi()){
            odlegloscOdStart(1, ws.getWierzcholek());
        }
        wKoniec.setOdlKoniec(0);
        for (Wierzcholek wT : this.getWierzcholki()) {
            if (wT.czyZawieraSasiada(wKoniec)) {
                odlegloscOdKoniec(1, wT);
            }
        }
        for(WierzcholekPlusPlus wk : wKoniec.getSasiedzi()){
            odlegloscOdKoniec(1, wk.getWierzcholek());
        }
        if(wStart.getOdlKoniec() != -1 && wKoniec.getOdlStart() != -1){
            return true;
        }
        return false;
    }

    public void odlegloscOdStart(int i, Wierzcholek w) {
        w.setOdlStart(i);
        for (WierzcholekPlusPlus wS : w.getSasiedzi()) {
            if (wS.getWierzcholek().getOdlStart() == -1 || wS.getWierzcholek().getOdlStart() > i) {
                wS.getWierzcholek().setOdlStart(i);
                odlegloscOdStart(i + 1, wS.getWierzcholek());
            }
        }
    }

    public void odlegloscOdKoniec(int i, Wierzcholek w) {
        w.setOdlKoniec(i);
        for (Wierzcholek wT : this.getWierzcholki()) {
            if (wT.czyZawieraSasiada(w)) {
                if (wT.getOdlKoniec() == -1 || wT.getOdlKoniec() > i) {
                    wT.setOdlKoniec(i);
                    odlegloscOdKoniec(i + 1, wT);
                }
            }
        }
    }

    public void sprawdzPoprawnosc() throws BladGrafu {
        //sprawdzam bledy konca
        for (Wierzcholek kon : koncowe) {
            if (!kon.isPoczatkowy()) {
                for (WierzcholekPlusPlus wppK : kon.getSasiedzi()) {
                    //koncowy nie moze pokazywac na nic
                    System.out.println("Blad konca");
                    throw new BladKonca();
                }
            }
        }
        //sprawdzam bledy poczatku
        for (Wierzcholek w : wierzcholki) {
            for (WierzcholekPlusPlus wpp : w.getSasiedzi()) {
                if(wpp.getWierzcholek().isPoczatkowy() && 
                        !wpp.getWierzcholek().isKoncowy() && !w.isPoczatkowy()){
                    //na poczatkowy nie moze pokazywac zaden poza poczatkowym 
                    //chyba ze sam jest tez koncowym
                    System.out.println("Blad poczatku");
                    throw new BladPoczatku();
                }
            }
        }
    }
}
